-
Notifications
You must be signed in to change notification settings - Fork 0
[25.01.01/ TASK-85] refactor dto and type #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough이 풀 리퀘스트는 프로젝트의 타입스크립트 구조와 응답 처리 방식을 개선하는 광범위한 변경 사항을 포함하고 있습니다. 주요 변경점은 DTO(데이터 전송 객체) 도입, 응답 형식 표준화, 경로 별칭(@/) 사용, 유효성 검사 미들웨어 개선 등입니다. 이러한 변경은 코드의 일관성, 가독성, 그리고 유지보수성을 향상시키는 데 초점을 맞추고 있습니다. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Controller
participant Service
participant Repository
Client->>Controller: 요청 전송
Controller->>Controller: 요청 유효성 검사
Controller->>Service: 서비스 메서드 호출
Service->>Repository: 데이터 조회/처리
Repository-->>Service: 데이터 반환
Service-->>Controller: 결과 반환
Controller->>Controller: DTO로 응답 구성
Controller-->>Client: 표준화된 응답 전송
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (19)
src/types/dto/responses/emptyReponse.type.ts (2)
3-4: 빈 인터페이스 대신 타입 alias 권장
정적 분석에서 지적한 것처럼, 빈 인터페이스는{}와 동등하므로type EmptyResponseData = Record<string, never>;와 같은 타입 alias를 고려해 보세요.-// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface EmptyResponseData {} +type EmptyResponseData = Record<string, never>;🧰 Tools
🪛 Biome (1.9.4)
[error] 3-4: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
5-9: 파일명 오탈자 확인 권장
파일명이emptyReponse.type.ts로 표기되어 있어,emptyResponse.type.ts와 일치하지 않아 혼동을 줄 수 있습니다. 일관성을 위해 파일명 수정도 고려해 주세요.src/types/dto/responses/loginResponse.type.ts (1)
13-25: 생성자 매개변수 순서 확인 제안생성자의 인자 순서가
success,message→id,username→profile→error로 되어 있습니다. 인자 순서를 변경할 계획이 있다면, 타입 안정성을 위해 유지보수 시 혼선을 줄일 방법을 고민해볼 수 있습니다. 현재 동작엔 문제 없어 보입니다.src/types/dto/requests/getAllPostsQuery.type.ts (1)
6-10: 인터페이스와 DTO의 역할 분리
GetAllPostsQuery인터페이스가 DTO 구조를 설명하고 있고,GetAllPostsQueryDto에서 실제 유효성 검사를 담당합니다. 이중 구조가 잘 유지되도록 문서화해두면 팀 내 혼선을 줄일 수 있습니다.src/configs/logger.config.ts (1)
29-29: JSON 포맷과 timestamp 결합 유의
JSON 포맷과 timestamp를 결합할 때, 가독성을 위해 필요한 경우 개발 환경에서만 다양한 로깅 레벨 혹은 별도의 로거 설정을 적용해 볼 수 있습니다.src/types/dto/responses/postResponse.type.ts (3)
3-13: 게시글 정보를 담는 인터페이스 정의
GetAllPostType는 게시글에 필요한 필드가 잘 정의되어 있습니다. 타입과 필드명도 명확해서 활용이 쉬울 것으로 예상됩니다.
20-31: PostsResponseDto 생성자로 DTO 일관성 확보
생성자에서data객체를 한 번에 만들어super로 넘기는 방식이 가독성 높습니다.
52-58: 통계 인터페이스의 필드 구성 주의
PostStatisticsType에서 필드가 많아 향후 필드 확장 시 코드가 복잡해질 수 있으므로, 적절히 도메인 단위로 구분할지 검토해 보세요.src/controllers/user.controller.ts (1)
Line range hint
24-38: 로그인 처리 시 쿠키 설정 및 DTO 사용
쿠키 설정 후LoginResponseDto로 응답을 보내는 흐름이 명확합니다. 다만, 쿠키 옵션 관련 환경 변수를 더욱 세분화할 여지가 있을 수 있습니다.src/services/post.service.ts (2)
50-50: 총 게시물 수 가져오기 로직 단순 호출
getTotalPostCounts에서 별도의 로직 없이 바로postRepo를 호출하므로, 도메인 로직이 복잡해질 경우 확장성에 유의해야 합니다.
55-70: 단일 게시물 조회 로직에서 에러 핸들링 주의
getPost메서드에서 조회 결과를 가공해 DTO형식으로 넘기기만 하므로, 데이터 누락 등 특수 케이스에 대한 방어 로직을 고려해 볼 수 있습니다.src/controllers/post.controller.ts (2)
25-25: [메서드 이름 일관성 확인]
this.postService.getAllposts메서드명이 기존getAllPost와 대소문자 표기에 일치하지 않아 가독성을 떨어뜨릴 수 있습니다. 일관된 네이밍을 권장합니다.-const result = await this.postService.getAllposts(id, cursor, sort, asc); +const result = await this.postService.getAllPosts(id, cursor, sort, asc);
35-35: [상태 코드 200 직접 지정]
정상 응답 시 200 코드를 사용한 것은 문제없습니다. 필요하다면 상수나 enum으로 관리하는 것도 방법입니다.src/repositories/post.repository.ts (6)
13-13: [정렬 컬럼 매핑 - dailyViewCount]
case 'dailyViewCount':로 매핑이 올바르게 처리되었습니다. 애플리케이션에서 enum 형태로 관리하면 오탈자를 줄이고 유지보수에 유리할 수 있습니다.
16-16: [정렬 컬럼 매핑 - dailyLikeCount]
위와 동일하게 enum 처리 방식이나 상수 관리를 고려해 보세요.
101-101: [마지막 포스트의 daily_like_count 사용]
위와 마찬가지로 null 처리 보강이 필요해 보입니다. 또 다른 정렬 기준 추가를 고려한다면 enum을 활용해 유지보수성을 높일 수 있습니다.
130-130: [getYesterdayAndTodayViewLikeStats 메서드 주석]
// ! pds.updated_at 은 FE 화면을 위해 억지로 9h 시간 더한 값임이라는 주석이 있습니다. 협업 시 혼란이 없도록 명확한 문서화 및 로직 보완을 고려해 보세요.
143-143: [오늘 날짜/TZ 비교 로직 확인]
(NOW() AT TIME ZONE 'UTC')::date로직이 장기적으로 유지 가능한지 검토 필요합니다. 자동 데이 라이트 세이빙 전환 등도 고려가 필요합니다.
148-148: [어제 날짜/TZ 비교 로직 확인]
마찬가지로 어제 날짜 판단 로직이 DST 같은 시점에서 문제없는지 확인 바랍니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (28)
src/configs/db.config.ts(1 hunks)src/configs/logger.config.ts(2 hunks)src/controllers/post.controller.ts(1 hunks)src/controllers/tracking.controller.ts(1 hunks)src/controllers/user.controller.ts(3 hunks)src/middlewares/validation.middleware.ts(1 hunks)src/repositories/post.repository.ts(6 hunks)src/repositories/tracking.repository.ts(1 hunks)src/repositories/user.repository.ts(2 hunks)src/routes/post.router.ts(2 hunks)src/routes/tracking.router.ts(2 hunks)src/routes/user.router.ts(2 hunks)src/services/post.service.ts(1 hunks)src/services/tracking.service.ts(1 hunks)src/types/dto/eventRequest.dto.ts(0 hunks)src/types/dto/requests/eventRequest.dto.ts(1 hunks)src/types/dto/requests/getAllPostsQuery.type.ts(1 hunks)src/types/dto/requests/getPostQuery.type.ts(1 hunks)src/types/dto/responses/baseResponse.type.ts(1 hunks)src/types/dto/responses/emptyReponse.type.ts(1 hunks)src/types/dto/responses/loginResponse.type.ts(1 hunks)src/types/dto/responses/postResponse.type.ts(1 hunks)src/types/index.ts(1 hunks)src/types/requests/getAllPostsQuery.type.ts(0 hunks)src/types/responses/baseResponse.type.ts(0 hunks)src/types/responses/loginResponse.type.ts(0 hunks)src/types/responses/postResponse.type.ts(0 hunks)src/types/responses/trackingReponse.type.ts(0 hunks)
💤 Files with no reviewable changes (6)
- src/types/requests/getAllPostsQuery.type.ts
- src/types/responses/trackingReponse.type.ts
- src/types/responses/loginResponse.type.ts
- src/types/dto/eventRequest.dto.ts
- src/types/responses/postResponse.type.ts
- src/types/responses/baseResponse.type.ts
🧰 Additional context used
🪛 Biome (1.9.4)
src/types/dto/responses/emptyReponse.type.ts
[error] 3-4: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
🔇 Additional comments (59)
src/types/dto/requests/eventRequest.dto.ts (3)
1-2: 클래스 검증 데코레이터 정상 동작 여부 확인
class-validator 모듈을 사용한 @IsEnum과 @IsNotEmpty 데코레이터가 올바르게 동작하려면, UserEventType이 올바른 열거형인지 및 해당 프로퍼티 값이 빈 값으로 들어오지 않는지 확인해 주세요.
4-7: 엔티티 정의 깔끔하게 잘 구성됨
EventRequestDto 클래스에 eventType 프로퍼티를 두고, 검증 데코레이터로 유효성을 보장하는 설계가 적절해 보입니다. 추가적인 프로퍼티가 필요하다면 동일한 방식으로 확장해 주세요.
9-11: 생성자 주입 방식 문제 없음
생성자를 통해 eventType을 주입하는 방식이 직관적입니다. 다른 곳에서 해당 DTO를 사용할 때도 일관된 생성 방식을 적용해 주세요.
src/types/dto/responses/baseResponse.type.ts (1)
1-13: API 응답 구조 표준화에 적합
BaseResponseDto<T>가 성공 여부, 메시지, 데이터, 오류를 일관된 형태로 제공하여, 다양한 API 응답을 통일된 구조로 다룰 수 있습니다. 응답 스키마 확장성도 좋아 보입니다.
src/types/dto/requests/getPostQuery.type.ts (3)
3-5: 유연한 파라미터 설계
PostParam 인터페이스에 postId를 선택적으로 정의하여, 여러 상황에서 재사용성이 높을 것으로 기대됩니다.
7-10: Optional 쿼리 설계
GetPostQuery에서 start와 end를 선택적으로 정의해 조회 범위를 확장할 수 있도록 한 점이 좋습니다.
20-23: 생성자 내부 변환 로직 확인 필요
생성자에서 start와 end를 그대로 할당하므로, 문자열 데이터를 변환 없이 단순히 유지합니다. Date 변환이 필요한 경우, 생성자 내부에서 new Date(start) 등을 호출하거나, DTO가 생성되기 전에 class-transformer를 통해 미리 변환하도록 검토해 주세요.
src/types/dto/responses/loginResponse.type.ts (2)
3-5: 인터페이스 정의가 직관적입니다.
ProfileType 인터페이스에 썸네일(프로필 이미지) 정보를 별도 속성으로 마련한 점이 명확합니다. 다른 프로필 정보가 확장될 가능성이 있다면, 별도를 고려해도 좋습니다.
7-11: 데이터 구조가 충분히 이해하기 쉽습니다.
LoginResponseData에 id, username, profile를 분리해 정의한 것은 직관적이며, 추후 확장성도 좋아 보입니다.
src/configs/db.config.ts (1)
14-14: 환경 변수 변경 시 설정 파일 재확인 필요
기존 POSTGRES_PORT 대신 DATA_PORT를 사용하고 있습니다. 배포 환경에서도 해당 환경 변수가 올바르게 설정되어 있는지 점검이 필요합니다.
src/types/dto/requests/getAllPostsQuery.type.ts (3)
1-3: 유효성 검사 및 변환 적용을 위한 올바른 import
class-transformer와 class-validator를 함께 사용하여 DTO를 구성하고 있습니다. 추후 전역 설정(예: plainToClass) 시 충돌 없이 잘 동작할지 확인해보세요.
4-5: 열거형 대신 문자열 타입 지정
'' | 'dailyViewCount' | 'dailyLikeCount' 형태는 충분히 단순하면서 의도를 잘 보여줍니다. 필요한 경우 enum 형태로 관리도 고려할 수 있습니다.
12-31: 클래스 생성자에서 기본값 설정이 깔끔합니다.
asc를 기본 false로 설정하고 sort가 없을 경우 ''로 대체하는 처리 로직이 명확하고 분명히 드러납니다.
src/routes/user.router.ts (2)
7-7: 함수명 변경 확인
validateDto → validateRequestDto로 변경되었습니다. 기존에 validateDto가 사용되는 다른 부분도 동일하게 변경되었는지 확인이 필요합니다.
18-18: 로그인 요청 시점에서의 DTO 유효성 검사 흐름
authMiddleware.login 다음에 validateRequestDto가 수행되도록 구성된 부분이 합리적입니다. 인증 과정과 DTO 유효성 검사가 기대하는 순서대로 동작하도록, 다른 라우트들에서도 일관성을 유지하세요.
src/services/tracking.service.ts (2)
9-10: tracking 메서드의 매개변수 이름이 명확해졌네요.
type에서 eventType으로 변경하여 의도가 분명해졌습니다. 현재 구현 로직엔 문제 없어 보입니다.
19-22: stayTime 계산 로직 추가가 적절합니다.
loadDate와 unloadDate간의 시간 차이를 밀리초 단위로 계산하는 로직이 명확합니다. 예외 처리를 통해 유효성 검증을 수행하므로 유지보수에 용이합니다.
src/routes/tracking.router.ts (2)
7-7: validateRequestDto로 변경된 점 확인했습니다.
함수명 변경으로 명확도가 향상되었습니다. 다른 라우트에서도 동일한 네이밍 컨벤션을 유지해주세요.
19-20: /event 및 /stay 라우트에 새 검증 미들웨어 적용
EventRequestDto와 StayTimeRequestDto 사용으로 요청 바디에 대한 형식 검증이 강화되었습니다.
src/routes/post.router.ts (3)
8-9: 쿼리 파라미터 검증을 위한 validateRequestDto와 DTO 임포트
쿼리 파라미터 검증 시 필요한 DTO를 명확히 가져오도록 수정되어 코드 가독성이 좋아졌습니다.
18-23: /posts 라우트에 쿼리 검증 로직 추가
쿼리값을 검증함으로써 안전성을 향상했습니다. 컨트롤러 로직을 간결하게 유지하기에도 좋습니다.
25-25: /post/:postId 라우트 추가
단일 포스트 조회 기능이 분리되어 사용 편의성이 좋아졌습니다.
src/middlewares/validation.middleware.ts (2)
6-6: RequestKey에 query 추가
이제 요청 쿼리에 대한 DTO 검증이 가능해졌습니다. 확장성 측면에서 합리적인 변경입니다.
9-9: 함수명을 validateRequestDto로 변경
validateDto → validateRequestDto로 범용성을 강조해 가독성이 높아졌습니다.
src/repositories/tracking.repository.ts (1)
Line range hint 25-37: 체류시간 저장 로직에 대한 유효성 검증 확인 필요
새로운 메서드 createStayTime이 체류시간과 관련된 정보를 그대로 DB에 저장하고 있습니다. 로직 자체는 간단하지만, 실제로 loadDate와 unloadDate의 유효성(예: loadDate가 unloadDate보다 미래 시점인지 여부 등) 검사나 예외 처리가 없는 점이 우려됩니다. 저장하기 전에 시계열 오류를 방지하고, 시간대(timezone) 차이를 고려할 필요가 있다면 추가 로직을 검토해 보시기 바랍니다.
src/configs/logger.config.ts (3)
15-22: JSON 포맷 전환에 따른 구조적 로깅 활용 권장
이제 로그가 JSON 구조로 출력되므로, 다양한 분석 툴(예: ELK 등)과 쉽게 연동 가능해집니다. 단, 콘솔 기반 디버깅 시 사람이 직접 읽기에 다소 불편할 수 있으니, 필요하다면 개발 환경에서만 기존 텍스트 형태 로그 포맷을 적용하는 방안도 고려할 수 있습니다.
27-27: 새로운 타임스탬프 포맷 확인
'YYYY-MM-DD HH:mm:ss.SSSZ' 형태로 바뀌어 밀리초 및 시간대가 표시되어 디버깅에 유용해졌습니다. 서버와 DB, 클라이언트 간 시간대가 일치하지 않는 상황에서 로깅 정보를 파악하기 쉽도록 유지하는 것을 권장합니다.
47-47: 에러 로그 파일명 패턴 변경 확인
에러 로그 파일명에 -error.log를 붙여 명확해졌습니다. 운영 환경(프로덕션)에서 에러 로그 분석 시 혼동 없이 빠르게 식별 가능해집니다.
src/controllers/tracking.controller.ts (3)
4-4: 새로운 DTO 임포트 확인
EmptyResponseDto 임포트를 통해 컨트롤러 응답 구조가 간결해졌습니다. 응답 형태가 다른 컨트롤러와 일관성을 유지하고 있는지 여부를 함께 확인해 보시기 바랍니다.
9-23: event 메서드 응답 구조 통일
event 메서드가 EmptyResponseDto를 사용하게 되어, 통일감 있는 응답 구조를 제공하게 되었습니다. 다만, eventType이 유효하지 않을 경우 예외 처리를 수행하는지 여부를 점검하고, 필요하다면 검증 로직 혹은 에러 메시지를 명확히 해 주시면 좋겠습니다.
25-39: stay 메서드 응답 구조 통일
마찬가지로 EmptyResponseDto를 사용하여 응답 포맷을 일관화했습니다. 내부적으로 TrackingService.stay가 id값의 유효성이나 날짜 범위 검증을 모두 처리하고 있는지 확인해 주시기 바랍니다.
src/types/index.ts (1)
8-20: 타입 및 DTO 재정비로 인한 구조 명확화
8~20번 라인에 걸쳐 다수의 DTO와 타입이 정리되어 있습니다. 사용되는 API별 Request/Response DTO를 명시적으로 구분함으로써, 추후 유지보수나 리팩터링 시 혼동을 줄이는 데 도움이 됩니다. 프로젝트 내에서 일관성 있게 적용되고 있는지 검증을 권장합니다.
src/types/dto/responses/postResponse.type.ts (6)
1-2: BaseResponseDto 활용 적절성 확인
이 파일에서는 BaseResponseDto를 잘 가져와 상속하고 있습니다. 전반적인 DTO 구조 확립에 도움이 될 것으로 보입니다.
15-18: 응답 구조 내 페이징 처리가 잘 반영됨
PostsResponseData에서 nextCursor와 posts를 합쳐 페이징 정보를 잘 표현하고 있습니다.
33-38: 하루 단위 조회/좋아요 수에 대한 구조화
GetPostType은 특정 날짜별 조회수·좋아요 수를 명확히 담아내고 있어, 일자별 통계 처리가 용이할 것으로 보입니다.
40-49: PostResponseDto로 개별 게시물 반환 시 가독성 상승
post 배열을 별도 필드로 묶어 반환하는 구조로, 클라이언트에서 데이터를 파싱하기가 간편해집니다.
60-63: PostStatisticsData로 게시글 통계 정보 구분
totalPostCount와 stats로 데이터가 분리되어 있어, 클라이언트에서 구조를 쉽게 이해할 수 있습니다.
65-76: PostStatisticsResponseDto로 성공/에러 케이스 일관성 확보
모든 결과를 BaseResponseDto 기반으로 응답 처리해, 에러 및 정상 응답 시 동일 구조를 유지합니다.
src/repositories/user.repository.ts (2)
Line range hint 19-37: 토큰 업데이트 로직 검증
updateTokens 메서드에서 UUID로 토큰을 갱신하고, 행이 없을 시 예외를 던지는 처리가 적절히 이루어져 있습니다.
Line range hint 50-72: 새 유저 생성 시 예외 처리 적절
createUser 메서드가 DB 삽입 후 성공 여부를 체크하고, 실패 시 예외를 던지는 접근이 안전하며, 로깅을 통해 장애 분석도 용이합니다.
src/controllers/user.controller.ts (3)
3-3: 필수 DTO들과 UserWithTokenDto 임포트
새로운 DTO(EmptyResponseDto, LoginResponseDto)와 token DTO를 한 번에 임포트해, 컨트롤러에서 일관된 응답 구조를 활용하는 점이 좋습니다.
47-53: 로그아웃 시 EmptyResponseDto로 구조 통일
빈 응답에도 DTO를 사용해 에러·성공 메시지 구조를 일원화함으로써 API 일관성을 유지하는 점이 좋습니다.
56-68: 현재 유저 조회에 대한 DTO 변환
fetchCurrentUser에서 조회된 user 정보를 DTO에 담아 반환하고 있으며, 필요한 필드만 추출해 응답하는 방식이 명확합니다.
src/controllers/post.controller.ts (11)
4-11: [import 문 관련 확인]
해당 DTO 임포트들이 정상적으로 추가되었는지 확인해 주세요. 필요 없는 임포트가 없고, 중복되는 임포트가 없는지 점검해 보시는 것을 권장합니다.
18-18: [타입 변경: Response]
함수 반환 타입이 Response<PostsResponseDto>로 변경되었습니다. DTO를 통해 응답 구조를 명확히 정의하는 것은 유지보수에 유리하므로 좋은 시도입니다.
23-24: [Query 파라미터 구조분해 확인]
cursor, sort, asc를 req.query에서 구조분해하여 바로 사용하고 있습니다. asc가 Boolean인지, 문자열인지 타입 체크 확인이 필요합니다.
27-33: [DTO 인스턴스 생성 로직]
PostsResponseDto에 성공 여부와 메시지를 함께 담고 있어 응답 표준화에 도움이 됩니다. 현재 구현은 명확하고 문제가 없어 보입니다.
42-46: [메서드 시그니처: getAllPostStatistics]
Response<PostStatisticsResponseDto>로 타입이 명시되어 있어 응답 형태가 명확합니다. 가독성과 유지보수성에 긍정적인 영향을 줄 것으로 보입니다.
53-59: [PostStatisticsResponseDto 사용]
통계 조회 시에도 DTO를 사용하여 일관된 응답을 제공하고 있습니다. 추가적인 필드가 필요할 경우 DTO를 확장해 사용하면 좋을 것 같습니다.
61-61: [응답 직후 처리]
res.status(200).json(response); 뒤에 추가 로직이 없다면 return 구문이 없어도 무방합니다. 함수 흐름 상 문제없어 보입니다.
68-72: [새 메서드: getPost 추가]
RequestHandler 형태 및 파라미터, 반환 타입이 명확하게 정의되어 있습니다. DTO를 통한 타입 안전성이 확보되어 보입니다.
73-76: [postId, start, end 파라미터 처리]
Number(req.params.postId)로 매개변수를 변환해 사용하는 것은 좋습니다. start, end도 적절히 분리되어 있어 로직 가독성이 좋습니다.
78-80: [단건 post DTO 생성]
new PostResponseDto(true, '단건 post 조회에 성공하였습니다.', post, null); 구문에서 기본 형태가 잘 갖춰져 있습니다. 추가 정보가 필요한 경우 DTO를 확장하세요.
82-86: [단건 조회 에러 처리]
에러 시 로그 출력 후 next(error)로 처리하고 있어 Express 에러 핸들링 플로우에 잘 맞습니다. 필요하다면 사용자에게 노출될 상세 메세지를 추가할 수 있습니다.
src/repositories/post.repository.ts (5)
8-8: [메서드 시그니처: findPostsByUserId]
함수 인자에 기본값(limit=15)을 지정한 부분은 합리적입니다. 파라미터가 많아 가독성이 다소 떨어질 수 있으므로, 필요 시 DTO로 묶는 방법도 고려해 보세요.
69-69: [오늘 날짜 비교 시 TZ 변환]
(date AT TIME ZONE 'Asia/Seoul' AT TIME ZONE 'UTC')::date = (NOW() AT TIME ZONE 'UTC')::date 구문으로 시간대를 엄격히 통제하고 있습니다. 의도한 대로 동작하는지 주기적인 확인이 필요할 것으로 보입니다.
74-74: [어제 날짜 비교 시 TZ 변환]
어제 날짜 비교 조건에서도 동일한 Time Zone 변환을 수행하고 있습니다. 운영 환경의 표준 시간대가 변경될 경우 로직 반영이 필요할 수 있습니다.
99-99: [마지막 포스트의 daily_view_count 사용]
sort === 'dailyViewCount' 조건에서 뷰 카운트를 사용하고 있습니다. 해당 값이 null인 경우를 고려하여 방어 로직이 필요할 수도 있습니다.
162-187: [새 메서드: findPostByPostId]
start, end 파라미터를 이용한 date 필터링으로 특정 기간 데이터를 조회할 수 있어 기능적 확장이 유연해 보입니다. 다만, start/end가 null일 때의 동작이 명확히 정의되었는지 확인해 주세요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🔭 Outside diff range comments (1)
src/repositories/user.repository.ts (1)
Line range hint
40-78: 사용자 생성 시 중복 검사가 필요합니다.이메일이나 UUID에 대한 중복 검사가 명시적으로 이루어지지 않고 있습니다. 데이터 무결성을 위해 사전 검증이 필요합니다.
다음과 같은 개선을 제안드립니다:
async createUser( uuid: string, email: string, encryptedAccessToken: string, encryptedRefreshToken: string, groupId: number, ): Promise<User> { try { + // 중복 검사 + const existingUser = await this.pool.query( + 'SELECT * FROM "users_user" WHERE velog_uuid = $1 OR email = $2', + [uuid, email] + ); + if (existingUser.rows[0]) { + throw new DBError('이미 존재하는 사용자입니다.'); + } + const query = ` INSERT INTO "users_user" (또한 데이터베이스 스키마에 unique 제약 조건 추가를 권장드립니다:
ALTER TABLE "users_user" ADD CONSTRAINT unique_velog_uuid UNIQUE (velog_uuid); ALTER TABLE "users_user" ADD CONSTRAINT unique_email UNIQUE (email);
🧹 Nitpick comments (11)
src/types/index.ts (1)
1-18: 코드 가독성 향상을 위한 그룹핑 제안타입과 DTO를 더 명확하게 구분하기 위해 주석을 추가하는 것이 좋겠습니다.
다음과 같이 수정하는 것을 제안합니다:
+// Model Types export type { User } from '@/types/models/User.type'; export type { Post } from '@/types/models/Post.type'; export type { PostDailyStatistics } from '@/types/models/PostDailyStatistics.type'; export type { PostStatistics } from '@/types/models/PostStatistics.type'; export type { UserEventTracking } from '@/types/models/UserEventTracking.type'; +// Velog Types export type { VelogUserLoginResponse } from '@/types/velog.type'; +// Request Types export type { GetAllPostsQuery } from '@/types/dto/requests/getAllPostsQuery.type'; export type { GetPostQuery, PostParam } from '@/types/dto/requests/getPostQuery.type'; +// Request DTOs export { StayTimeRequestDto } from '@/types/dto/requests/stayTimeRequest.dto'; export { GetAllPostsQueryDto } from '@/types/dto/requests/getAllPostsQuery.type'; export { GetPostQueryDto } from '@/types/dto/requests/getPostQuery.type'; export { EventRequestDto } from '@/types/dto/requests/eventRequest.type'; +// Response DTOs export { LoginResponseDto } from '@/types/dto/responses/loginResponse.type'; export { EmptyResponseDto } from '@/types/dto/responses/emptyResponse.type'; export { PostsResponseDto, PostResponseDto, PostStatisticsResponseDto } from '@/types/dto/responses/postResponse.type'; +// Other DTOs export { UserWithTokenDto } from '@/types/dto/userWithToken.type'; export { VelogUserLoginDto } from '@/types/dto/velogUser.type';src/types/dto/responses/loginResponse.type.ts (2)
3-5: ProfileType 인터페이스 개선 제안현재 thumbnail 필드만 포함되어 있습니다. 사용자 프로필에 일반적으로 포함되는 다음과 같은 추가 필드들의 포함을 고려해보시기 바랍니다:
- displayName
- bio
- createdAt
interface ProfileType { thumbnail: string; + email?: string; + displayName?: string; + bio?: string; + createdAt?: Date; }
13-13: 클래스 문서화 추가 제안BaseResponseDto를 상속받는 목적과 사용 방법에 대한 JSDoc 문서화를 추가하면 좋을 것 같습니다.
+/** + * 로그인 응답을 위한 DTO 클래스 + * @extends BaseResponseDto<LoginResponseData> + * @example + * const response = new LoginResponseDto(); + * response.data = { + * id: 1, + * username: "user", + * profile: { thumbnail: "url" } + * }; + */ export class LoginResponseDto extends BaseResponseDto<LoginResponseData> {}tsconfig.json (1)
26-26: 테스트 설정 파일(jest.config.ts)을 포함하려는 의도 확인
테스트 범위에jest.config.ts를 포함해 의도가 맞다면 그대로 진행해도 좋습니다. 혹시 불필요하게 빌드 대상에 포함되지 않는지 유의하세요.Dockerfile (2)
8-9: pnpm 설치 후 nvm, Yarn 등 다른 패키지 관리자는 삭제해도 좋습니다.
이미지 크기 최적화를 위해, 사용하지 않는 패키지 매니저(예: Yarn, npm) 관련 의존성이 설치되어 있다면 제거를 고려하세요.
17-19: 소스 코드 빌드 후 dist 폴더만 남깁니다.
빌드 결과물을 활용하는 로직이 명확하므로, 빌드 성능 보강을 위해 필요 없는 devDependencies를 최소화하세요.package.json (1)
8-8: 빌드 스크립트 단순화
--build옵션을 제거하고tsc로만 수행하면, 빌드 속도는 빨라질 수 있으나 프로젝트 규모가 커질 경우 점진 빌드를 활용하지 못할 수 있습니다.ecosystem.config.js (3)
6-6: 인스턴스 수에 대한 검토가 필요합니다.현재 단일 인스턴스로 설정되어 있는데, 서비스의 가용성을 높이기 위해 클러스터 모드 사용을 고려해보시는 것이 어떨까요? CPU 코어 수에 따라 자동으로 인스턴스를 생성하도록 설정할 수 있습니다.
- instances: 1, + instances: 'max',
1-1: ESLint 경고 해결 방안ESLint에서 'module is not defined' 경고가 발생하고 있습니다. Node.js 환경임을 명시하기 위해 파일 상단에 다음 주석을 추가하는 것이 좋습니다.
+/* eslint-env node */ module.exports = {🧰 Tools
🪛 eslint
[error] 1-1: 'module' is not defined.
(no-undef)
5-5: 빌드 경로 주석 형식 개선인라인 한글 주석은 가독성을 해칠 수 있습니다. JSDoc 형식으로 변경하는 것이 좋겠습니다.
- script: 'dist/index.js', // 빌드된 메인 파일 경로 + /** 빌드된 메인 파일 경로 */ + script: 'dist/index.js',src/types/dto/velogUser.dto.ts (1)
8-11: 생성자 활용 시 class-validator 동작 방식을 유의하세요
생성자를 통해 thumbnail을 받는 것은 DTO 사용 시 명시적 초기화를 유도한다는 장점이 있습니다.
다만, class-validator가 생성자 파라미터가 아닌 실제 인스턴스 필드를 검증한다는 점을 유념해, DTO 사용 흐름에서 혼동이 없도록 주의해 주세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (32)
.dockerignore(1 hunks)Dockerfile(1 hunks)docker-compose.yml(1 hunks)ecosystem.config.js(1 hunks)jest.config.ts(1 hunks)package.json(2 hunks)src/controllers/post.controller.ts(1 hunks)src/controllers/tracking.controller.ts(1 hunks)src/controllers/user.controller.ts(3 hunks)src/middlewares/auth.middleware.ts(1 hunks)src/middlewares/errorHandling.middleware.ts(1 hunks)src/middlewares/validation.middleware.ts(1 hunks)src/modules/__test__/test.aes.encryption.test.ts(2 hunks)src/repositories/post.repository.ts(4 hunks)src/repositories/tracking.repository.ts(2 hunks)src/repositories/user.repository.ts(3 hunks)src/routes/post.router.ts(2 hunks)src/routes/tracking.router.ts(2 hunks)src/routes/user.router.ts(2 hunks)src/services/post.service.ts(2 hunks)src/services/tracking.service.ts(1 hunks)src/services/user.service.ts(1 hunks)src/types/dto/requests/eventRequest.type.ts(1 hunks)src/types/dto/responses/emptyReponse.type.ts(1 hunks)src/types/dto/responses/loginResponse.type.ts(1 hunks)src/types/dto/responses/postResponse.type.ts(1 hunks)src/types/dto/velogUser.dto.ts(1 hunks)src/types/dto/velogUser.type.ts(1 hunks)src/types/express.d.ts(1 hunks)src/types/index.ts(1 hunks)src/types/models/UserEventTracking.type.ts(1 hunks)tsconfig.json(2 hunks)
✅ Files skipped from review due to trivial changes (8)
- .dockerignore
- src/types/models/UserEventTracking.type.ts
- src/types/express.d.ts
- src/modules/test/test.aes.encryption.test.ts
- docker-compose.yml
- src/middlewares/errorHandling.middleware.ts
- src/middlewares/auth.middleware.ts
- src/services/user.service.ts
🚧 Files skipped from review as they are similar to previous changes (11)
- src/services/post.service.ts
- src/repositories/tracking.repository.ts
- src/routes/post.router.ts
- src/middlewares/validation.middleware.ts
- src/routes/tracking.router.ts
- src/routes/user.router.ts
- src/controllers/user.controller.ts
- src/controllers/post.controller.ts
- src/services/tracking.service.ts
- src/types/dto/responses/postResponse.type.ts
- src/repositories/post.repository.ts
🧰 Additional context used
🪛 eslint
ecosystem.config.js
[error] 1-1: 'module' is not defined.
(no-undef)
🪛 Biome (1.9.4)
src/types/dto/responses/emptyReponse.type.ts
[error] 3-4: An empty interface is equivalent to {}.
Safe fix: Use a type alias instead.
(lint/suspicious/noEmptyInterface)
🔇 Additional comments (30)
src/types/index.ts (1)
1-18: 응답 값 표준화가 잘 이루어졌습니다PR의 목적대로 응답 DTO를 통한 응답 값 표준화가 잘 이루어졌으며, 경로 별칭(@/types/)을 사용하여 일관성 있게 구현되었습니다. 전반적인 구조가 깔끔하고 명확합니다.
src/types/dto/responses/loginResponse.type.ts (2)
1-1: 깔끔한 import 구문입니다!경로 별칭(@)을 사용하여 가독성과 유지보수성이 향상되었습니다.
7-11: LoginResponseData 인터페이스 검증 필요현재 구조는 명확하나, 다음 사항들을 확인해주시기 바랍니다:
- 로그인 응답에 필요한 모든 필드가 포함되어 있는지
- 토큰이나 인증 관련 정보가 필요하지는 않은지
- 다른 API 엔드포인트들과의 응답 구조 일관성
✅ Verification successful
토큰 정보가 별도로 관리되고 있어 현재 구조가 적절함
코드베이스 분석 결과, 다음과 같은 사항들이 확인되었습니다:
- 토큰 관련 정보는
req.tokens를 통해 별도로 관리되고 있으며, 쿠키를 통해 처리됩니다.LoginResponseData인터페이스는 클라이언트에 필요한 기본 사용자 정보만을 포함하고 있어 응답 구조가 적절합니다.- 다른 API 응답들과 비교했을 때 일관된 구조를 유지하고 있습니다.
BaseResponseDto를 상속받아 표준화된 응답 형식을 따르고 있습니다.현재 구조를 유지하시면 됩니다.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: 다른 응답 DTO들의 구조를 확인하여 일관성 검증 # 모든 response DTO 파일 검색 echo "=== Response DTO 구조 분석 ===" fd -e ts -e tsx --full-path "src/types/dto/responses" --exec ast-grep --pattern 'interface $INTERFACE_NAME { $$$ }'Length of output: 3028
Script:
#!/bin/bash # Description: 인증 관련 응답 구조와 토큰 필드 확인 # 인증 관련 파일에서 토큰이나 인증 정보 검색 echo "=== 인증 관련 응답 구조 분석 ===" rg -i "token|auth|login" src/types/dto/responses -A 5 # API 호출 부분에서 로그인 응답 사용 확인 echo -e "\n=== 로그인 API 응답 사용 분석 ===" rg -i "loginresponse|login.*response" src/ -A 5Length of output: 5515
src/repositories/user.repository.ts (2)
2-4: 상대 경로에서 별칭 경로로의 변경이 잘 되었습니다!경로 별칭(@)을 사용하여 import 구문을 정리한 것이 코드의 가독성과 유지보수성을 향상시켰습니다.
Line range hint
21-38: 토큰 업데이트 로직 검증이 필요합니다.토큰 형식에 대한 유효성 검사가 누락되어 있습니다. 잘못된 형식의 토큰이 데이터베이스에 저장될 수 있습니다.
토큰 형식 검증 로직을 추가하는 것을 권장드립니다. 다음 스크립트로 현재 프로젝트의 토큰 검증 패턴을 확인해보겠습니다:
jest.config.ts (1)
7-9: 절대 경로 매핑 설정이 잘 되었습니다.
@/경로로 소스 디렉토리를 매핑하면, 모듈 import 시 유지보수성과 가독성이 향상됩니다.tsconfig.json (2)
3-10: TypeScript 구성의 모던화가 잘 이루어졌습니다.
ES2022를 대상으로 NodeNext 모듈 해석을 사용하면, 최신 문법 사용 시 호환성이 좋아집니다.baseUrl과paths설정도 프로젝트 내 import 시 편의성을 높이는 데 유용합니다.
23-24: Synthetic default import 허용에 주의하세요.
상황에 따라 ESM 환경에서 호환성이 달라질 수 있으므로, 외부 라이브러리 import 방식이 충돌 없는지 확인해주세요.Dockerfile (5)
1-3: 멀티 스테이지 빌드 구조가 명확합니다.
애플리케이션 빌드와 프로덕션 이미지를 분리하여 최종 이미지 크기를 줄이고 효율을 높일 수 있습니다.
14-15: 프로덕션에서도 frozen-lockfile 사용 권장
동일한 lockfile을 사용하도록npm ci혹은pnpm install --frozen-lockfile방식으로 일관된 의존성 관리를 유지하는 점은 좋습니다.
30-32: 프로덕션 환경 의존성 최소화
pnpm install --prod로 프로덕션에 필요한 모듈만 설치하는 접근이 좋습니다. 다른 환경에서만 필요한 모듈을 제거해 최종 이미지 크기를 줄일 수 있습니다.
38-38: 포트 노출 작업이 명확합니다.
Dockerfile에서 EXPOSE 3000 설정으로 컨테이너 간 트래픽 제어가 용이합니다.
40-40: pm2-runtime 사용으로 프로덕션 안정성 강화
pm2-runtime으로 무중단 운영 및 자동 재시작을 제공해 서버 안정성을 높이는 선택이 적절합니다.package.json (2)
14-15: 테스트 커버리지 스크립트가 구체적으로 정의되어 있습니다.
test:coverage스크립트를 통해 CI에서도 코드 품질을 점검 가능하므로 상당히 유용합니다.
58-60: 최신 TypeScript와 transform-paths 플러그인 도입
절대 경로 설정을 지원하고, 최신 TypeScript 구성을 활용할 수 있습니다. 프로젝트 전반에서 경로 변환이 잘 동작하는지 확인해 주세요.ecosystem.config.js (1)
1-18: PM2 설정이 전반적으로 잘 구성되어 있습니다.설정이 깔끔하게 구성되어 있으며, 로깅과 메모리 제한이 적절하게 설정되어 있습니다.
🧰 Tools
🪛 eslint
[error] 1-1: 'module' is not defined.
(no-undef)
src/types/dto/requests/eventRequest.type.ts (3)
2-2: [임포트] 추가된 class-validator 확인
코드 유효성 검사를 위해class-validator를 사용한 점이 좋아 보입니다. 별다른 문제 없이 정상 동작할 것으로 예상됩니다.
3-9: [enum] UserEventType 정의 검토
UserEventType열거형을 사용하여 이벤트 타입을 명확하게 구분한 점이 가독성과 유지보수성 측면에서 좋습니다. 각 이벤트 타입에 짧은 문자열을 매핑한 것도 식별 용도로 적절해 보입니다.
Line range hint
10-16: [DTO] EventRequestDto 유효성 검사
@IsEnum과@IsNotEmpty를 통해eventType에 대해 명확한 검증 규칙을 부여한 점이 좋습니다. 생성자 역시 명확하게 값을 할당하여 DTO 사용을 간결화합니다. 추후 확장 시 필요한 필드가 있다면 빠르게 추가할 수 있어 보입니다.src/types/dto/responses/emptyReponse.type.ts (1)
5-5: [DTO] EmptyResponseDto의 BaseResponseDto 상속 구조 확인
EmptyResponseDto가BaseResponseDto를 통해 성공 여부와 메시지를 관리하는 구조가 명확하고 좋습니다. 이로써 빈 데이터를 표현할 때도 일관된 응답 형식을 유지할 수 있습니다.src/controllers/tracking.controller.ts (2)
9-23: [컨트롤러] event 메서드 로직 검토
eventType을 바디에서 추출 후 서비스 단으로 전달하는 구현은 Controller-Service 간 역할 분리를 잘 지켰습니다. 또한EmptyResponseDto를 통해 성공 메시지와 상태를 일관성 있게 반환하는 점이 좋습니다.
25-39: [컨트롤러] stay 메서드 로직 검토
stay메서드에서 체류 시간을 계산하고EmptyResponseDto로 결과를 반환하는 구현이 명확합니다. 예외 발생 시 logger를 통한 에러 로깅 처리도 잘 되어있습니다.src/types/dto/velogUser.dto.ts (1)
4-7: ProfileDTO 클래스 분리로 인한 가독성 상승
ProfileDTO를 별도 클래스로 정의함으로써 응집도가 높아지고 명확도가 향상되었습니다.
@IsString() 데코레이터 역시 문자열 필드 검증에 적합해 보입니다.src/types/dto/velogUser.type.ts (7)
1-3: 모듈화 및 외부 라이브러리 사용이 적절합니다.
class-validator와class-transformer를 통한 DTO 검증 및 변환 설정이 적절하게 구성되었습니다.
5-7: UUID 검증 어노테이션 설정이 적절합니다.
@IsUUID()를 사용해id속성의 유효성을 보장하는 방식이 좋습니다.
8-10: 문자열 검증이 잘 구성되었습니다.
@IsString()로username에 대한 기본 검증을 수행하는 점이 좋습니다.
11-13: 이메일 검증 로직이 적절합니다.
@IsEmail()로 이메일 형식 검증을 간결하게 처리하는 점이 바람직합니다.
14-16: 중첩 객체 검증 설정이 적절합니다.
@ValidateNested()와@Type(() => ProfileDTO)를 함께 사용해서profile속성을 중첩 검증하는 구조가 효과적입니다.
18-23: 생성자를 통한 속성 주입이 명료합니다.
생성자에서 모든 속성을 명확히 주입해 가독성이 뛰어납니다.
25-32: 클래스 접근성 문제
ProfileDTO클래스가 export되지 않고 있지만, 외부 모듈에서 사용할 가능성이 있다면export키워드로 공개하는 편이 좋습니다. 반면 내부 전용이라면 현재 상태도 무방합니다.
six-standard
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
conflict만 해결하면 괜찮을 듯 합니다!
좋았던 점
- 확실해진 타입
이전에 비해서 타입이 확실해져서 읽기 편했습니다 - 확장성 높은 타입
빈 타입이나 기본 타입 등 확장 시 유용한 타입들이 많이 보였습니다
추후 새 기능을 개발하게 되어도 빠르게 개발이 가능할 듯 합니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/types/dto/requests/getPostQuery.type.ts (1)
15-17:⚠️ Potential issue날짜 타입 검증과 실제 타입 불일치 가능성
@IsDate()데코레이터와string타입 선언이 일치하지 않습니다. 이는 런타임에서 타입 불일치 문제를 일으킬 수 있습니다.
🧹 Nitpick comments (1)
src/types/dto/requests/getPostQuery.type.ts (1)
8-11: 인터페이스 네이밍 컨벤션 개선 필요
GetPostQuery인터페이스는 DTO 클래스의 기본 형태를 정의하고 있으므로,IGetPostQuery와 같이 인터페이스임을 명시하는 접두사를 사용하는 것이 좋습니다.- export interface GetPostQuery { + export interface IGetPostQuery { start?: string; end?: string; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/types/dto/requests/getPostQuery.type.ts(1 hunks)src/types/dto/responses/emptyReponse.type.ts(1 hunks)tsconfig.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/types/dto/responses/emptyReponse.type.ts
- tsconfig.json
Nuung
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋았던 점
- 와우 DTO 다 바꿨네요! 대박, 리펙토링 꽤 많이 걸리셨겠어요
- 상대경로에서 번들링을 통한 경로 매핑도 아주 좋았습니다. 보통 FE 에서 이렇게 하죠
- 그리고 nest 로 넘어가면 이렇게 세팅이 자동으로 되죠!
- 오히려 express 를 선택하시면서 구조화에 대한 이해가 훨씬 좋았을 것 같아요!
아쉬운 점
- 해당 부분들이 build 나 도커라이징에 대한 이슈가 있었는지 없었는지 검증이 없네요
- 혹시 문제 없었나요~?
- request & response 에 대한 모든 DTO 들이 있으니, 이제 swagger 세팅하는 것은 일도 아닐 것 같은데! swagger 는 언제쯤 고대되나요?
변경한 점
Summary by CodeRabbit
릴리즈 노트
새로운 기능
버그 수정
리팩터링
성능 개선